﻿using System;
using System.Linq;
using Mailjet.Client;
using CRM.Extensions;
using CRM.Models.Email;
using CRM.ViewModels.Email;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using Mailjet.Client.Resources;
using System.Collections.Generic;
using CRM.Models.GlobalSearch;
using CRM.Services.SystemManage;
using Microsoft.Extensions.Logging;
using Mailjet.Client.TransactionalEmails;
using Microsoft.EntityFrameworkCore;
using PointsConsumptionLog = CRM.Models.PointsConsumptionLog;

namespace CRM.Services.Email
{
    public class MailjetApplicationService : BaseService
    {
        private readonly MailjetClient _mailjetClient;
        private readonly CompanyService _companyService;
        private readonly CompanyPointsConfigService _companyPointsConfigService;
        private EmailMarketingService _emailMarketingService;  
        private readonly ILogger<MailjetApplicationService> _logger;
        
        private const string SenderEmail = "kuajing@nanjing.com";
        public const string ApiName = "MailjetClient";
        private static SendContact _sendContact;
        private static SendContact SendContact => _sendContact ??= new SendContact(SenderEmail);

        public MailjetApplicationService(IMailjetClient mailjetClient, ILogger<MailjetApplicationService> logger,CompanyService companyService,CompanyPointsConfigService companyPointsConfigService,EmailMarketingService emailMarketingService)
        {
            _mailjetClient = mailjetClient as MailjetClient;
            _logger = logger;
            _companyService = companyService;
            _companyPointsConfigService = companyPointsConfigService;
            _emailMarketingService = emailMarketingService;
        }

        public async Task RunAsync(EmailMarketing emailMarketing)
        {
            DbContext.Entry(emailMarketing).State = EntityState.Unchanged;
            // 营销任务加锁
            var res = await _emailMarketingService.SetLockedStatus(emailMarketing.Id,emailMarketing.UserId,true);
            if (!res)
            {
                return;
            }
            var json = emailMarketing.AddresseeObj;
            if (json == null)
            {
                _logger.LogInformation("没有收件人信息,跳过发送邮件");
                return;
            }
            var jsonAddressee = json.Chunk(50);
            var companyConfig = _companyService.GetInfo(emailMarketing.CompanyId);

            if (companyConfig == null)
            {
                _logger.LogError("无法找到公司id为{CompanyId}的数据,跳过发送邮件", emailMarketing.CompanyId);
                return;
            }
            var numberOfPoints = companyConfig.NumberOfPoints;
            // TODO: 为每个公司拿单独的配置项,目前拿的是通用的
            // 配置项快照
            var companyPointsConfig = _companyPointsConfigService.GetInfo(emailMarketing.CompanyId) ?? _companyPointsConfigService.GetInfo(1);
            var expectsTheRestOfTheIntegral = numberOfPoints - json.Count * companyPointsConfig.SendEmailPoints;
            //  TODO: 判断预计积分是否够使用 【 --未加锁,后期需要对积分进行加锁(预防同一时间建立的大量任务) 】
            // 进入发送环节后积分允许为负,发送前必须大于〇
            if (numberOfPoints >= 0 && expectsTheRestOfTheIntegral >= 0)
            {
                foreach (var jsonAddresseeChunk in jsonAddressee)
                {
                    await SendEmailWithMax50Receipt(emailMarketing, jsonAddresseeChunk,companyPointsConfig.SendEmailPoints);
                    // Thread.Sleep(2000);
                }
            }
            else
            {
                await _emailMarketingService.SetState(emailMarketing.Id,EmailMarketing.StateEnum.Canceled, EmailMarkeingLog.TypeEnum.Negative,"积分不足，营销任务被自动取消。");
                // TODO: 加字段记录失败原因,json,记录 Message + 时间戳 ？？？ 待验证
            }
            // 营销任务解锁
            await _emailMarketingService.SetLockedStatus(emailMarketing.Id,emailMarketing.UserId,false);
        }
        
        public record AddresseeObjectT(int? id, string name=default, string email="");

        private static JObject BulkDataObject(int emailMarketingId, AddresseeObj addresseeObj)
        {
           return  new JObject
            {
                // {
                //     "From",
                //     new JObject
                //     {
                //         {"Email", SendContact.Email},
                //         {"Name", SendContact.Name ?? ""}
                //     }
                // },
                {
                    "To",
                    new JArray
                    {
                        new JObject
                        {
                            {"Email", addresseeObj.Addressee},
                            {"Name", addresseeObj.Name}
                        }
                    }
                },
                {
                    "Vars", new JObject() { {"readUrl", EmailMarketingService.BuildReadUrl("http://crm.mimaosou.com", emailMarketingId, addresseeObj.Addressee)}}
                }
                // {"Subject", emailMarketing.EmailSubject},
                // {"HTMLPart", emailMarketing.EmailContent}
            };
        }

        private async Task SendEmailWithMax50Receipt(EmailMarketing emailMarketing, IEnumerable<AddresseeObj> json,int SendEmailPoints)
        {
            var effectiveSendNum = 0;
            var effectiveSendAddressee = new List<AddresseeObj>();
            // 邮件内容过长时批量发送会将内容复制50次，导致发送的body过长，请求失败
            // https://dev.mailjet.com/email/guides/send-api-v31/#send-in-bulk Set global payload properties
            // 将相同的邮件内容放在Globabls中，避免body过长
            JObject globalData = new JObject()
            {
                {
                    "From", new JObject
                            {
                                {"Email", SendContact.Email},
                                {"Name", SendContact.Name ?? ""}
                            }
                },
                {"Subject", emailMarketing.EmailSubject},
                {"HTMLPart", emailMarketing.EmailContent + "<img src='[[var:readUrl]]' />"}
            };
            var bulkData = new JArray();
            foreach (var addresseeObj in json)
            {
                bulkData.Add(BulkDataObject(emailMarketing.Id, addresseeObj));
            }
            // TODO: 对API请求参数和结果存储
            var request = new MailjetRequest { Resource = new ResourceInfo("send", type: ResourceType.Send, apiVersion: ApiVersion.V3_1) }
                .Property("Globals", globalData)
                .Property(Send.Messages, bulkData);
            var response = await _mailjetClient.PostAsync(request);
            // 加Api请求日志
            var apiName = ApiName;
            var apiNameHashCode = apiName.GetFixedHashCode();
            var log = new ApiInvokedLog()
            {
                ApiName = apiName,
                ApiNameHashCode = apiNameHashCode,
                ParamsJson = request.ToString(),
                ResponseJson = response.Content.ToString(),
                UserId = emailMarketing.UserId,
                GroupId = emailMarketing.GroupId,
                CompanyId = emailMarketing.CompanyId,
                OemId = emailMarketing.OemId,
                EmailMarketingId = emailMarketing.Id
            };
            DbContext.Add(log);
            _logger.LogInformation(response.GetData().ToString());
            if (response.IsSuccessStatusCode)
            {
                var res = response.GetData().ToObject<JArray>();
                if (response.Content.Count > 0)
                {
                    emailMarketing.State = EmailMarketing.StateEnum.Completed;
                    var dic = emailMarketing.AddresseeObj.ToDictionary(x => x.Addressee, x => x);
                    if (res != null)
                    {
                        foreach (var tempa in res)
                        {
                            if (tempa["Status"]?.ToString() == "success")
                            {
                                Console.WriteLine("成功记录开始\n");
                                Console.WriteLine("----------------------------------------------------\n");
                                _logger.LogInformation("Endpoint接口触发, 请求参数：{Response}", tempa);
                                foreach (var recordListObj in tempa["To"])
                                {
                                    var MessageUUIDRecord = recordListObj["MessageUUID"].ToString();
                                    var MessageIDRecord = (long) recordListObj["MessageID"];
                                    var MessageHrefRecord = recordListObj["MessageHref"].ToString();
                                    var addressee = recordListObj["Email"].ToString();
                                    var recordList = new EmailSendHistoryVM.emailResultRecord(MessageUUIDRecord,
                                        MessageIDRecord, MessageHrefRecord, addressee);
                                    var customerData = dic[addressee] ?? new AddresseeObj();
                                    var data = EmailSendHistoryVM.NewMailjetModel(emailMarketing, addressee, SenderEmail,
                                        customerData, recordList);
                                    DbContext.Add(data);
                                    if (SendEmailPoints != 0)
                                    {
                                        effectiveSendAddressee.Add(customerData);
                                    }
                                }

                                Console.WriteLine("----------------------------------------------------\n");
                                Console.WriteLine("成功记录结束\n");
                                // TODO: 有效发出数量具体计算还得看API计费规则,目前是按发出不成功不计费
                                effectiveSendNum = effectiveSendNum + 1;
                                
                            }
                            else if (tempa["Status"]?.ToString() == "error")
                            {
                                //邮件内容缺失或者格式不正确导致的错误
                                Console.WriteLine("错误记录开始");
                                Console.WriteLine("----------------------------------------------------\n");
                                foreach (var rec in tempa["Errors"])
                                {
                                    Console.WriteLine(rec["ErrorCode"].ToString());
                                    Console.WriteLine(rec["ErrorIdentifier"].ToString());
                                    Console.WriteLine(rec["ErrorMessage"].ToString());
                                    Console.WriteLine((int) rec["StatusCode"]);
                                    Console.WriteLine(rec["ErrorRelatedTo"].ToString());
                                }

                                Console.WriteLine("----------------------------------------------------\n");
                                Console.WriteLine("错误记录结束");
                            }
                        }
                    }

                    var sendingNum = response.Content["Messages"].Count();
                    var sendingNumHistory = emailMarketing.SendingNum;
                    emailMarketing.SendingNum =  sendingNumHistory + sendingNum;
                    // 计算有效发出数量并扣除积分
                    if (SendEmailPoints != 0)
                    {
                        // 扣积分
                        var effectiveSendPoints = effectiveSendNum * SendEmailPoints;
                        var companyModel = DbContext.Company.First(m => m.Id == emailMarketing.CompanyId);
                        var numberOfPoints = companyModel.NumberOfPoints;
                        companyModel.NumberOfPoints = numberOfPoints - effectiveSendPoints;
                        // 记录积分日志
                        var consumptionType = PointsConsumptionLog.ConsumptionTypeEnum.SendingEmailByServer;
                        var UserInfo = DbContext.Users.First(m => m.Id == emailMarketing.UserId);
              
                        var ext = new JObject()
                        {
                            {
                                "Addressee" ,  JArray.FromObject(effectiveSendAddressee)
                            },
                            {
                                "Id", emailMarketing.Id
                            },
                            {
                                "EmailMarketingName", emailMarketing.Title
                            },
                            {
                                "TimingTransmission",emailMarketing.TimingTransmission
                            }
                        };
               
                        var pointsConsumptionLogData = new PointsConsumptionLog()
                        {
                            UserId = emailMarketing.UserId,
                            GroupId = emailMarketing.GroupId,
                            CompanyId = emailMarketing.CompanyId,
                            OemId = emailMarketing.OemId,
                            ConsumptionType = consumptionType,
                            Ext = ext.ToString(),
                            OperateUser = UserInfo.TrueName,
                            PointsNum = effectiveSendPoints
                        };
                        DbContext.PointsConsumptionLog.Add(pointsConsumptionLogData);
                    }
                }
                else
                {
                    // 除非API异常
                    emailMarketing.State = EmailMarketing.StateEnum.Canceled;
                }
            }
            else
            {
                // TODO:发送失败的错误原因
                // 记录异常以及数据，放到运维模块UI展示，对接飞书群，便于及时处理
                // Console.WriteLine(string.Format("StatusCode: {0}\n", response.StatusCode));
                // Console.WriteLine(string.Format("ErrorInfo: {0}\n", response.GetErrorInfo()));
                // Console.WriteLine(response.GetData());
                // Console.WriteLine(string.Format("ErrorMessage: {0}\n", response.GetErrorMessage()));
            }
            // 保存数据库
            await DbContext.SaveChangesAsync();
        }
    }
}